/**
 * 
 */
package research.sbookmarking.process;

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;

import org.afox.util.RMethod;
import org.connotea.Post;
import org.connotea.Tag;

import research.sbookmarking.AppController;
import research.sbookmarking.process.util.StringUtils;

/**
 * This class controller for processing the data retrieved from Connotea.org
 * <p> 
 * @author <A HREF="mailto:aatleung@gmail.com">Albert Leung</a>
 * @version 1.0
 */
public class ProcessController {

	private static ProcessController anInstance = null;
	
	/**
	 * The only way to instantiate this class is through 
	 * {@link #getInstance() getInstance}
	 */
	private ProcessController() {
	}

	@SuppressWarnings({ "unchecked" })
	protected int calcURLUserTag (ObjectInputStream stream, int uid, TreeMap<String,Object> dateTreeMap) throws IOException, ClassNotFoundException{
		try {
			while (true){
				Iterator<Post> results = ((List<Post>)stream.readObject()).iterator();
				
				while (results.hasNext()){
					Post aPost = results.next();

					
					TreeMap<String,Object> urlTreeMap = new TreeMap<String,Object>();
					TreeMap<String,Object> userTreeMap = new TreeMap<String,Object>();

					//java.text.SimpleDateFormat format = new java.text.SimpleDateFormat ("dd/MM/yyyy H:mm");
					//TimeZone gstTime = TimeZone.getTimeZone("GMT"); 
					//format.setTimeZone(gstTime);
					
					//String date = format.format(aPost.getCreated());
					String url = aPost.getBookmark().getLink().toString(); 

					userTreeMap.put(aPost.getCreator(),StringUtils.convert(aPost.getSubjects().iterator()));
					urlTreeMap.put(url, userTreeMap);
					dateTreeMap.put(Integer.toString(uid), urlTreeMap);
					uid++;
				}
				stream.readObject();
			}
		}
		catch (EOFException e){
			return uid;
		}
	}

	@SuppressWarnings({ "unchecked", "unused" })
	private int calcURLUnique (ObjectInputStream stream, String command, TreeMap<String,Object> urlTreeMap) throws IOException, ClassNotFoundException{
		try {
			while (true){
				Iterator<Post> results = ((List<Post>)stream.readObject()).iterator();
				
				while (results.hasNext()){
					Post aPost = results.next();

					String url = aPost.getBookmark().getLink().toString();
					List temp = (List)urlTreeMap.get(url);
					if (temp==null){
						temp = (List)RMethod.invoke(aPost, command, new ArrayList(0));
					}
					else {
						AppController.getInstance().copyUnique(temp, RMethod.invoke(aPost, command, new ArrayList(0)));
					}
					
					RMethod.invoke(temp, "trimToSize", new ArrayList(0));

					urlTreeMap.put(url, StringUtils.convert(temp));
				}
				stream.readObject();
				System.gc();
			}
			
		} 
		catch (EOFException e){
		}
		return 1;
	}

	@SuppressWarnings({ "unchecked", "unused" })
	private int calcURL (ObjectInputStream stream, String command, TreeMap<String,Object> urlTreeMap) throws IOException, ClassNotFoundException{
		try {
			while (true){
				Iterator<Post> results = ((List<Post>)stream.readObject()).iterator();
				
				while (results.hasNext()){
					Post aPost = results.next();

					String url = aPost.getBookmark().getLink().toString();
					List temp = (List)urlTreeMap.get(url);
					if (temp == null){
						temp = StringUtils.convertToList(RMethod.invoke(aPost, command, new ArrayList()));
					}
					else {
						AppController.getInstance().copy(temp, StringUtils.convert(RMethod.invoke(aPost, command, new ArrayList(0))));
					}
					
					try {
						RMethod.invoke(temp, "trimToSize", new ArrayList(1));
					}
					catch (RuntimeException e){
						
					}

					urlTreeMap.put(url, temp);
					
				}
				stream.readObject();
			}
			
		} 
		catch (EOFException e){
		}
		return 1;
	}

	@SuppressWarnings({ "unchecked", "unused" })
	private int calcUserUniqueTags (ObjectInputStream stream, TreeMap<String,Object> userTreeMap) throws IOException, ClassNotFoundException{
		try {
			while (true){
				Iterator<Post> results = ((List<Post>)stream.readObject()).iterator();
				
				while (results.hasNext()){
					Post aPost = results.next();

					String username = aPost.getCreator();
					List tags = (List)userTreeMap.get(username);
					if (tags != null){
						AppController.getInstance().copyUnique(tags, StringUtils.convert(aPost.getSubjects().iterator()));
					}
					else {
						tags = (List)StringUtils.convert(aPost.getSubjects());
					}
					
					try {
						RMethod.invoke(tags, "trimToSize", new ArrayList(1));
					}
					catch (RuntimeException e){
						
					}

					userTreeMap.put(username,tags);
				}
				stream.readObject();
			}
			
		} 
		catch (EOFException e){
		}
		return 1;
	}

	@SuppressWarnings({ "unchecked", "unused" })
	private int calcUserTags (ObjectInputStream stream, TreeMap<String,Object> userTreeMap) throws IOException, ClassNotFoundException{
		try {
			while (true){
				Iterator<Post> results = ((List<Post>)stream.readObject()).iterator();
				
				while (results.hasNext()){
					Post aPost = results.next();

					String username = aPost.getCreator();

					TreeMap tagFreq = (TreeMap)userTreeMap.get(username);
					if (tagFreq == null) {
						tagFreq = new TreeMap();
					}

					Iterator tags = aPost.getSubjects().iterator();
					
					while (tags.hasNext()){
						String tag = StringUtils.convertToString(tags.next());
						int value = 0;
						
						if (tagFreq.containsKey(tag)){
							Double freq = (Double)tagFreq.get(tag);
							value = freq.intValue();
						}
						
						tagFreq.put(tag, Double.valueOf(++value));
					}
					
					userTreeMap.put(username,tagFreq);
				}
				stream.readObject();
			}
			
		} 
		catch (EOFException e){
		}
		return 1;
	}

	@SuppressWarnings({ "unchecked", "unused" })
	private int calcTags (ObjectInputStream stream, TreeMap<String,Object> tagTreeMap) throws IOException, ClassNotFoundException{
		try {
			while (true){
				Iterator<Post> results = ((List<Post>)stream.readObject()).iterator();
				
				while (results.hasNext()){
					Post aPost = results.next();

					Iterator <Tag> tags = aPost.getSubjects().iterator();
					while (tags.hasNext()){
						Tag tag = tags.next();
						Double freq = (Double)tagTreeMap.get(tag.getValue());
						double value =0;
						if (freq!=null){
							value = freq.doubleValue();
						}
						tagTreeMap.put(tag.getValue(), Double.valueOf(++value));
					}
				}
				stream.readObject();
			}
			
		} 
		catch (EOFException e){
		}
		return 1;
	}

	@SuppressWarnings({ "unchecked", "unused" })
	private int calcUser (ObjectInputStream stream, TreeMap<String,Object> tagTreeMap) throws IOException, ClassNotFoundException{
		try {
			while (true){
				Iterator<Post> results = ((List<Post>)stream.readObject()).iterator();
				
				while (results.hasNext()){
					Post aPost = results.next();

					Double freq = (Double)tagTreeMap.get(aPost.getCreator());
					double value =0;
					if (freq!=null){
						value = freq.doubleValue();
					}
					tagTreeMap.put(aPost.getCreator(), Double.valueOf(++value));
				}
				stream.readObject();
			}
			
		} 
		catch (EOFException e){
		}
		return 1;
	}

	@SuppressWarnings({ "unchecked", "unused" })
	private int calcTime (ObjectInputStream stream, String command, TreeMap<String,List<Date>> TreeMap) throws IOException, ClassNotFoundException{
		try {
			List param = new ArrayList();
			while (true){
				Iterator<Post> results = ((List<Post>)stream.readObject()).iterator();
				
				while (results.hasNext()){
					Post aPost = results.next();
					param.add(aPost);

					Iterator<String> keys = StringUtils.convert(((List)RMethod.invoke(this,command.toLowerCase(),param)).iterator()).iterator();
					param.clear();
					while (keys.hasNext()){
						String key = keys.next();
						List<Date> temp = TreeMap.get(key); 
						if (temp==null){
							temp = new ArrayList(1);
							temp.add(aPost.getCreated());
						}
						else {
							int index = 0;
							if (aPost.getCreated().after(temp.get(0)) ||
								aPost.getCreated().equals(temp.get(0))){
								
								index = temp.size();
							}
							temp.add(index,aPost.getCreated());
						}
						TreeMap.put(key, temp);
					}
					
				}
				stream.readObject();
			}
			
		} 
		catch (EOFException e){
		}
		return 1;
	}

	public final List<String> user(Post aPost){
		List<String> list = new ArrayList<String>(1); 
		list.add(aPost.getCreator());
		return list;
	}
	
	public final List<String> url(Post aPost){
		List<String> list = new ArrayList<String>(1); 
		list.add(aPost.getBookmark().getLink().toString());
		return list;
	}
	
	public final List<Tag> tag(Post aPost){
		return aPost.getSubjects();
	}
	
	/**
	 * Ensures that there is only one ProcessController instance. If an
	 * instance already exists it return the address of that instance
	 * otherwise it will instantiate an instance and save it.
	 * <p>
	 * @return an instance of this object.
	 */
	public static ProcessController getInstance() {
		if (anInstance==null) {
			anInstance = new ProcessController();
		}
		
		return anInstance;
	}

	public Object processData (String command, ArrayList<Object> param){
		return RMethod.invoke(this, command, param);
	}
		
/*
	public void processData (List<DataContainer> dataContainers){
		Iterator<DataContainer> iterator = dataContainers.iterator();
		
		while (iterator.hasNext()){
			processData(iterator.next());
		}
	}

	/* For Debugging purposes
	 * 
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
	 */
}
